package com.fasterxml.jackson.databind;

import com.fasterxml.jackson.databind.cfg.ConfigFeature;


public enum SerializationFeature implements ConfigFeature {
    /**
     * 根值是否序列化
     */
    WRAP_ROOT_VALUE(false),

    /**
     * 美化输出，缩进格式输出JSON
     */
    INDENT_OUTPUT(false),


    /**
     * 序列化空Bean时, 是否抛出异常，默认抛出异常。
     * 空Bean即没有任何属性的Bean，或者有属性但是没有对应的get方法。
     */
    FAIL_ON_EMPTY_BEANS(true),

    /**
     * 自身循环引用时，是否抛出异常，默认抛出异常。
     *
     * @since 2.4
     */
    FAIL_ON_SELF_REFERENCES(true),

    /**
     * 包装异常，在序列化对象时如果出现异常，会捕获异常，进行包装后再抛出，以提供更详细的错误信息
     */
    WRAP_EXCEPTIONS(true),

    /**
     * 序列化时，如果已要求JSON中包含对象的类型信息，但是又有@JsonUnwrapped注解，则序列化失败。@JsonUnwrapped会去除对象结构，直接平铺对象内的属性
     *
     * @since 2.4
     */
    FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS(true),

    /**
     * 自身循环引用，序列化为null
     *
     * @since 2.11
     */
    WRITE_SELF_REFERENCES_AS_NULL(false),


    /**
     * 对象实现了Closeable接口，序列化后自动调用close()方法。默认禁用(不调用close()方法)。
     */
    CLOSE_CLOSEABLE(false),

    /**
     * writeValue序列化之后，是否调用JsonGenerator的flush
     */
    FLUSH_AFTER_WRITE_VALUE(true),


    /* TODO 特定数据类型的配置 */
    /*TODO 日期类型*/
    /**
     * 日期类型序列化成时间戳。如果禁用默认使用StdDateFormat(yyyy-MM-dd'T'HH:mm:ss.SSSX)格式化日期
     */
    WRITE_DATES_AS_TIMESTAMPS(true),

    /**
     * Map日期类型的key序列化为时间戳。默认禁用，使用StdDateFormat(yyyy-MM-dd'T'HH:mm:ss.SSSX)格式化日期
     */
    WRITE_DATE_KEYS_AS_TIMESTAMPS(false),

    /**
     * 序列化日期上的时区ID。默认禁用。启用时，日期的后面会带上时区ID，这种日期反序列化可能会有问题。
     *
     * @since 2.6
     */
    WRITE_DATES_WITH_ZONE_ID(false),

    /**
     * 使用ObjectMapper上下文中的时区序列化日期，对没有时区信息的日期类型无效。默认启用。禁用则使用默认的时区进行序列化日期。
     *
     * @since 2.13
     */
    WRITE_DATES_WITH_CONTEXT_TIME_ZONE(true),

    /**
     * Duration类型的对象序列化为时间戳。
     *
     * @since 2.5
     */
    WRITE_DURATIONS_AS_TIMESTAMPS(true),

    /*TODO CHAR数组*/
    /**
     * char数组序列化为json数组，禁用时会序列化为字符串
     */
    WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false),

    /*TODO 枚举*/
    /**
     * 举值的序列化方式。启用时，使用Enum.toString()的返回值；禁用时，使用Enum.name()的返回值。
     */
    WRITE_ENUMS_USING_TO_STRING(false),

    /**
     * 枚举值的序列化方式。启用时，枚举序列化为数字(序号，从0开始)，使用Enum.ordinal()的返回值。禁用时，枚举序列化为文本。默认禁用。
     */
    WRITE_ENUMS_USING_INDEX(false),

    /**
     * 枚举值的序列化方式。枚举作为Map的key时，序列化为数字(序号)。默认禁用。
     *
     * @since 2.10
     */
    WRITE_ENUM_KEYS_USING_INDEX(false),

    /*TODO 集合*/
    /**
     * Map中null值的序列化方式。启用时，序列化null值；禁用时，不序列化null值。建议使用JsonInclude.Include.NON_NULL过滤null
     */
    @Deprecated // since 2.9
            WRITE_NULL_MAP_VALUES(true),

    /**
     * 空集合、空数组的序列化方式。启用时，序列化为空数组；禁用时，不序列化。默认启用。对Map无效。建议使用JsonInclude.Include.NON_EMPTY过滤空集合、空数组。
     */
    @Deprecated // since 2.8
            WRITE_EMPTY_JSON_ARRAYS(true),

    /**
     * 只有单个元素的集合、数组的序列化方式。启用时，正常序列化为数组；禁用时，不序列化为数组(去掉了层级)。默认禁用。
     */
    WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED(false),

    /*TODO BIGDECIMAL*/
    /**
     * 启用时，使用BigDecimal.toPlainString()的返回值；禁用时，使用BigDecimal.toString()的返回值，可能出现科学计数法。
     * 从2.5版本开始废弃，建议使用JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN。
     * BigDecimal有三个toString()方法：
     * toEngineeringString：有必要时使用工程计数法。工程记数法与科学技术法类似，但要求10的幂必须是3的倍数；
     * toPlainString：不使用任何指数；
     * toString：有必要时使用科学计数法。
     */
    @Deprecated // since 2.5
            WRITE_BIGDECIMAL_AS_PLAIN(false),

    /**
     * 是否使用纳秒时间戳写入数字时间戳值
     * @since 2.2
     */
    WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS(true),

    /**
     * 序列化Map时按Key进行排序。启用：排序；禁用：不排序。默认禁用。
     */
    ORDER_MAP_ENTRIES_BY_KEYS(false),

    /**
     * Jackson 会在序列化期间主动获取并缓存所有的序列化器，这可以提高序列化的性能，因为序列化器不需要在序列化过程中动态创建。
     * @since 2.1
     */
    EAGER_SERIALIZER_FETCH(true),

    /**
     * Jackson 序列化对象时会调用 equals() 方法来确定对象引用的唯一性，而不是依赖 Object.hashCode()。
     * 注意，这个特性可能会影响序列化的性能，因为它可能会导致比使用 hashCode() 更慢的 equals() 方法调用。只有当你确实需要依据对象的内容而不是引用来序列化对象时，才应该考虑启用这个特性。
     * @since 2.3
     */
    USE_EQUALITY_FOR_OBJECT_ID(false);

    private final boolean _defaultState;
    private final int _mask;

    private SerializationFeature(boolean defaultState) {
        _defaultState = defaultState;
        _mask = (1 << ordinal());
    }

    @Override
    public boolean enabledByDefault() {
        return _defaultState;
    }


    @Override
    public int getMask() {
        return _mask;
    }

    @Override
    public boolean enabledIn(int flags) {
        return (flags & _mask) != 0;
    }
}
